package com.sun.talk.netty

import com.alibaba.fastjson.JSON
import com.sun.talk.enums.MsgActionEnum
import com.sun.talk.service.UserService
import com.sun.talk.service.impl.UserServiceImpl
import com.sun.talk.utils.SpringUtils
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame
import io.netty.util.concurrent.GlobalEventExecutor
import io.netty.channel.group.DefaultChannelGroup
import io.netty.channel.group.ChannelGroup
import org.springframework.beans.factory.annotation.Autowired
import java.time.LocalDateTime

class TextWebSocketHandler : SimpleChannelInboundHandler<TextWebSocketFrame>() {

    //记录管理所有客户端channel
    companion object{
        val users: ChannelGroup = DefaultChannelGroup(GlobalEventExecutor.INSTANCE)
    }

    override fun handlerAdded(ctx: ChannelHandlerContext){
        println("新客户端加入")
        users.add(ctx.channel())
    }

    override fun handlerRemoved(ctx: ChannelHandlerContext) {
        println("新客户端离开")
        users.remove(ctx.channel())
    }

    override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
        cause.printStackTrace()
        //发生异常 关闭连接
        ctx.channel().close()
        users.remove(ctx.channel())
    }
    override fun channelActive(ctx: ChannelHandlerContext) {
        println("与客户端建立连接，通道开启！")
    }

    override fun channelInactive(ctx: ChannelHandlerContext?) {
        println("与客户端断开连接，通道关闭！")
    }
    override fun channelRead0(ctx: ChannelHandlerContext, msg: TextWebSocketFrame) {
        println("客户端收到服务器数据:" + msg.text())

        val currentChannel = ctx.channel()
        //1.获取消息
        val content = msg.text()
        //2.判断消息类型
        val dataContent = JSON.parseObject(content, DataContent::class.java)
        when(dataContent.action){
            //2.1 第一次open时 将channel与userId关联
            MsgActionEnum.CONNECT.type ->{
                val senderId = dataContent.chatMsg.senderId
                UserChannelRel.put(senderId,currentChannel)
            }
            //2.2 聊天类型 聊天记录保存数据库 标记消息的签收状态[未签收]
            MsgActionEnum.CHAT.type ->{
                val chatMsg = dataContent.chatMsg
                //保存消息到数据库 并标记为未读
                val userService = SpringUtils.getBean(UserService::class.java)
                val msgId = userService.saveMsg(chatMsg)
                chatMsg.msgId = msgId
                val dataContentMsg = DataContent(chatMsg = chatMsg)
                //发送消息
                val receiverChannel = UserChannelRel.get(chatMsg.receiverId)
                if(receiverChannel == null){
                    //TODO 代表用户离线 推送消息
                }else{
                    val findChannel = users.find(receiverChannel.id())
                    if(findChannel != null) {
                        //用户在线
                        receiverChannel.writeAndFlush(TextWebSocketFrame(
                                JSON.toJSONString(dataContentMsg)
                        ))
                    }else {
                        //TODO 代表用户离线 推送消息
                    }
                }
            }
            //2.3 签收消息类型 针对具体的消息签收 修改签收状态[已签收]
            MsgActionEnum.SIGNED.type ->{
                val userService = SpringUtils.getBean(UserService::class.java)
                //需要去签收的消息id 逗号分隔
                val msgIdsStr = dataContent.extend
                val msgIds = msgIdsStr.split(",").filter { it.isNotEmpty() }
                if(msgIds.isNotEmpty()){
                    //批量签收
                    userService.updateMsgSigned(msgIds)
                }
            }
            //2.4 心跳类型
            MsgActionEnum.KEEPALIVE.type ->{
                println("收到心跳包")
            }
        }
    }
}